﻿using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;

using SBPweb.Localization;

namespace SBPweb.Modules.Modularity
{
    /// <summary>
    /// This class represents some information about Module.
    /// </summary>
    public class ModuleDescriptor
    {

		#region Private & Protected members
		
		/// <summary>
		/// byte[] mRawData
		/// </summary>
		private byte[] mRawData;
		/// <summary>
		/// string mModuleTypeName
		/// </summary>
        protected string mModuleTypeName;
        /// <summary>
        /// FileInfo pFileInfo
        /// </summary>
		protected FileInfo pFileInfo;
        /// <summary>
        /// bool pLoaded
        /// </summary>
		protected bool pLoaded;
        /// <summary>
        /// bool pInitialized
        /// </summary>
		protected bool pInitialized;
        /// <summary>
        /// string pAssemblyName
        /// </summary>
		protected string pAssemblyName;
        /// <summary>
        /// System.Version pAssemblyVersion
        /// </summary>
		protected System.Version pAssemblyVersion;
		/// <summary>
		/// System.Version pFileVersion
		/// </summary>
		protected string pFileVersion;
		/// <summary>
		/// string pFileName
		/// </summary>
		protected string pFileName;
		/// <summary>
		/// Assembly pAssembly
		/// </summary>
		protected Assembly pAssembly;
		/// <summary>
		/// ConstructorInfo pConstructorInfo
		/// </summary>
		protected ConstructorInfo pConstructorInfo;
		/// <summary>
		/// ModuleProfile pModuleProfile
		/// </summary>
		protected ModuleProfile pModuleProfile;

		#endregion

		#region Constructor logic

		internal ModuleDescriptor(FileInfo fileInfo, ModuleProfile mp)
        {
            try
            {
				pFileInfo = fileInfo;
				pLoaded = false;
				pInitialized = false;

				mRawData = null;
                mModuleTypeName = null;

                mRawData = GetBytes(fileInfo.FullName);
				pAssembly = Assembly.LoadFrom(fileInfo.FullName);
				pAssemblyName = pAssembly.GetName().Name;
				pAssemblyVersion = pAssembly.GetName().Version;

				pFileName = pFileInfo.FullName;

				FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(fileInfo.FullName);
				pFileVersion = fvi.FileVersion;

				object obj = ResourceHandler.GetAssemblyCustomAttribute<AssemblyDefaultAliasAttribute>(pAssembly);

                mModuleTypeName = obj.ToString();

				Type type = pAssembly.GetType(mModuleTypeName);
				pConstructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(IModuleHost) }, null);

				pModuleProfile = mp;

            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("FileInfo parameter error ({0})!", fileInfo.FullName), ex);
            }
		}

        public static ModuleDescriptor CreateInstance(FileInfo fileInfo)
        {
            ModuleProfile mp = ModuleProfile.CreateInstance(fileInfo);
            return new ModuleDescriptor(fileInfo, mp);
        }

		#endregion

		#region Properties

		/// <summary>
		/// Raw data of assembly
		/// </summary>
		internal byte[] RawData
        {
            get
            {
                return mRawData;
            }
        }

        /// <summary>
        /// Name of the entrypoint Type of Module
        /// </summary>
        public string ModuleTypeName
        {
            get
            {
                return mModuleTypeName;
            }
        }

        /// <summary>
        /// FileInfo of Module
        /// </summary>
		public FileInfo FileInfo
		{
			get
			{
				return pFileInfo;
			}
		}

        /// <summary>
        /// This property is true if module is loaded
        /// </summary>
		public bool Loaded
		{
			get
			{
				return pLoaded;
			}
			internal set
			{
				pLoaded = value;
			}
		}

        /// <summary>
        /// This property is true if module is initialized
        /// </summary>
        public bool Initialized
		{
			get
			{
				return pInitialized;
			}
			internal set
			{
				pInitialized = value;
			}
		}

        /// <summary>
        /// AssemblyName of the Module
        /// </summary>
		public string AssemblyName
		{
			get
			{
				return pAssemblyName;
			}
		}

        /// <summary>
        /// AssemblyVersion of the Module
        /// </summary>
		public System.Version AssemblyVersion
		{
			get
			{
				return pAssemblyVersion;
			}
		}

		/// <summary>
		/// FileVersion of the Module
		/// </summary>
		public string FileVersion
		{
			get
			{
				return pFileVersion;
			}
		}

		/// <summary>
		/// Full name of the assembly file
		/// </summary>
		public string FileName
		{
			get
			{
				return pFileName;
			}
		}

		/// <summary>
		/// The Assembly instance of the module
		/// </summary>
		internal Assembly Assembly
		{
			get
			{
				return pAssembly;
			}
		}

		/// <summary>
		/// The ConstructorInfo instance of the module
		/// </summary>
		internal ConstructorInfo ConstructorInfo
		{
			get
			{
				return pConstructorInfo;
			}
		}

		/// <summary>
		/// The ModuleProfile instance of the module
		/// </summary>
		public ModuleProfile ModuleProfile
		{
			get
			{
				return pModuleProfile;
			}
		}

		#endregion

		#region Internal methods

		internal static byte[] GetBytes(string path)
        {
            byte[] rawData;
            FileStream fS = new FileStream(path, FileMode.Open, FileAccess.Read);
            int length = (int)fS.Length;
            rawData = (byte[])Array.CreateInstance(typeof(byte), length);
            fS.Read(rawData, 0, length);
            fS.Close();

            return rawData;
		}

		#endregion

	}
}